
class waferGroup:
    def __init__(self,ID):
        self.ID=ID
        if ID==1 or ID==2:
            self.path='ACD'
        elif ID==3 or ID==4 or ID==9 or ID==10:
            self.path='ABCD'
        elif ID==5 or ID==6 or ID==11 or ID==12:
            self.path='DBA'
        elif ID==7 or ID==8:
            self.path='ABC'
        self.nowStep=0
        self.finish=False

    def nextStep(self):
        if not self.finish:
            self.nowStep+=1
            if self.nowStep==len(self.path):
                self.finish=True

    def verifyStep(self,factoryRepoID):
        return factoryRepoID==self.path[self.nowStep]

    def getProgress(self):
        return self.nowStep/len(self.path)

allWafer=[]
for i in range(1, 13):
    allWafer.append(waferGroup(i))

class box:
    def __init__(self,ID,w:waferGroup):
        self.ID=ID
        self.wafer=w

    def isEmpty(self):
        return self.wafer is None

    def load(self,wafer):
        if not self.wafer is None:
            self.wafer=wafer
        else:
            return False

    def unload(self):
        if self.wafer is None:
            return False
        else:
            w=self.wafer
            self.wafer=None
            return w


class baseTruck:
    def __init__(self,aroundBuilding:list):
        self.aroundBuilding = aroundBuilding
        self.nowPos = aroundBuilding[0] # 目前的位置
        # 目前的状态
        self.destination = None
        self.remainTime = None

    def setTask(self,destination,remainTime):
        self.destination=destination
        self.remainTime=remainTime

    def isStop(self):
        return self.remainTime is None

    def update(self):
        if not self.remainTime is None:
            self.remainTime-=1
        # 走完了还得更新当前位置
        if self.remainTime==0:
            self.nowPos=self.destination
            self.destination=None
            self.remainTime=None


class boxTruck(baseTruck):
    def __init__(self, aroundBuilding:list): # aroundBuilding: 0仓库，1装卸站A，2装卸站B
        baseTruck.__init__(self, aroundBuilding)
        self.maxNum=1 # 这个是晶圆盒数量
        self.allBox=[]

    def moveTo(self,destination):
        if self.isStop():
            if self.nowPos==self.aroundBuilding[0]: # 现在在仓库
                if destination!=self.aroundBuilding[0]: # 目的地是装卸站
                    self.setTask(destination,20)
                    return True
                else:
                    return False
            else: # 现在在装卸站
                if destination==self.aroundBuilding[0]: # 目的地是仓库
                    self.setTask(destination,20)
                    return True
                elif destination!=self.nowPos: # 不能往同一个地方走
                    self.setTask(destination,15)
                    return True
                else:
                    return False
        else:
            return False

    # 只能装卸晶圆盒
    def loadBox(self,ID): # 返回成功与否
        if self.isStop():
            b=self.nowPos.unloadBox(ID) # boxTruck周围的建筑一定是boxRepo
            if b==False: # 没有要卸的晶圆盒
                return False
            else:
                if len(self.allBox)+1>self.maxNum:
                    return False
                else:
                    self.allBox.append(b)
                    return True
        else:
            return False

    def unloadBox(self,ID): # 返回成功与否
        if self.isStop():
            for i in self.allBox:
                if i.ID==ID:
                    if self.nowPos.loadBox(i)==False:
                        return False
                    else:
                        self.allBox.remove(i)
                        return True
            return False
        else:
            return False


class truckA(baseTruck):
    def __init__(self, aroundBuilding:list): # aroundBuilding: 装卸站A，装卸站B，合并站
        baseTruck.__init__(self, aroundBuilding)
        self.maxNum = 1
        self.allGroup = []  # 目前装载的晶圆

    def moveTo(self,destination):
        if self.isStop():
            if self.nowPos==self.aroundBuilding[2]: # 现在在合并站
                if destination!=self.aroundBuilding[2]: # 目的地是装卸站
                    self.setTask(destination,25)
                    return True
                else:
                    return False
            else: # 现在在装卸站
                if destination==self.aroundBuilding[2]: # 目的地是合并站
                    self.setTask(destination,25)
                    return True
                elif destination != self.nowPos:  # 不能往同一个地方走
                    self.setTask(destination,15)
                    return True
                else:
                    return False
        else:
            return False

    def loadFromBox(self,ID): # 返回成功与否。ID是box ID
        if self.isStop():
            if self.nowPos!=self.aroundBuilding[2]: # 只有在装卸站才能从晶圆盒里取
                b=self.nowPos.unloadBox(ID) # 先连盒带晶圆卸下来
                if b!=False: # 盒存在
                    w=b.unload() # 晶圆从盒里卸下来
                    if w!=False: # 晶圆存在
                        if len(self.allGroup)+1<=self.maxNum: # 把晶圆转移到车里
                            self.allGroup.append(w) # 晶圆装车
                            self.nowPos.loadBox(b) # 空盒再装回去
                            return True
                        else: # 没地方装
                            return False
                    else: # 晶圆不存在
                        return False
                else: # 盒不存在
                    return False
            else:
                return False
        else:
            return False

    # 晶圆ID和晶圆盒ID不需要对应，找个空盒装就行。因此传入晶圆ID，用任意一个空盒装，返回盒的ID
    def unloadToBox(self,ID): # 返回装入盒的ID，参数的ID是晶圆ID
        if self.isStop():
            if self.nowPos != self.aroundBuilding[2]:  # 只有在装卸站才能往晶圆盒里装
                for i in self.allGroup:
                    if ID==i.ID:
                        # 找空盒
                        if self.nowPos.allBox[0].isEmpty(): # 装卸站，只有一个晶圆盒
                            self.nowPos.allBox[0].load(i)
                            self.allGroup.remove(i)
                            return True
                        else:
                            return False
            else:
                return False
        else:
            return False

    # 在合并站，直接操作晶圆
    def load(self,ID): # 返回成功与否
        if self.isStop():
            if self.nowPos==self.aroundBuilding[2]: # 从合并站卸，装到车上
                w = self.nowPos.unload(ID)
                if w == False:  # 没有要卸的晶圆盒
                    return False
                else:
                    if len(self.allGroup) + 1 > self.maxNum:
                        return False
                    else:
                        self.allGroup.append(w)
                        return True
            else:
                return False
        else:
            return False

    def unload(self,ID): # 返回成功与否
        if self.isStop():
            if self.nowPos==self.aroundBuilding[2]:
                for i in self.allGroup:
                    if i.ID == ID:  # 找到了
                        if self.nowPos.load(i)==False:
                            return False
                        else:
                            self.allGroup.remove(i)
                            return True
                return False
            else:
                return False
        else:
            return False


class truckB(baseTruck):
    def __init__(self, aroundBuilding:list):
        baseTruck.__init__(self, aroundBuilding)
        self.maxNum = 2
        self.allGroup=[]

    def moveTo(self, destination):
        if self.isStop():
            if self.nowPos!=destination:
                self.setTask(destination,15)
                return True
            else:
                return False
        else:
            return False

    def load(self,ID): # 返回成功与否
        if self.isStop():
            w = self.nowPos.unloadBox(ID)  # 先连盒带晶圆卸下来
            if w==False:
                return False
            else:
                if len(self.allGroup) + 1 <= self.maxNum:  # 从厂里移到车里
                    self.allGroup.append(w)
                    return True
                else:
                    return False
        else:
            return False

    def unload(self, ID):  # 返回成功与否
        if self.isStop():
            for i in self.allGroup:
                if i.ID == ID:  # 找到了
                    if self.nowPos.load(i) == False:
                        return False
                    else:
                        self.allGroup.remove(i)
                        return True
            return False
        else:
            return False


class factoryTask:
    def __init__(self):
        # 保存目前的加工任务和状态
        self.remainTime=None

    def update(self):
        if not self.remainTime is None:
            self.remainTime-=1
        if self.remainTime==0:
            self.remainTime=None
            return True # 任务完成，子类需重载update，接收到返回true后要做相应反应


class boxRepo: # 存的是晶圆盒
    def __init__(self,type):
        self.allBox=[]

        if type=='mainRepo': # 仓库
            for i in range(1,13):
                self.allBox.append(box(i,allWafer[i]))
            self.maxNum = 12
        else: # 装卸站
            self.maxNum = 1

    def loadBox(self,b:box): # 返回成功与否
        if len(self.allBox)+1>self.maxNum:
            return False
        else:
            self.allBox.append(b)
            return True

    def unloadBox(self,ID): # 返回晶圆盒对象
        for i in self.allBox:
            if i.ID==ID:
                b=i
                self.allBox.remove(i)
                return b
        return False


class repo: # 存的是晶圆
    def __init__(self):
        self.maxNum = 2 # 都是最多10晶圆
        self.allGroup=[]

    def load(self,w:waferGroup): # 返回成功与否
        if len(self.allGroup)+1>self.maxNum:
            return False
        else:
            self.allGroup.append(w)
            return True

    def unload(self,ID): # 返回晶圆对象
        for i in self.allGroup:
            if i.ID==ID:
                w=i
                self.allGroup.remove(i)
                return w
        return False


class factoryRepo(repo,factoryTask): # 晶圆工厂
    def __init__(self,ID):
        factoryTask.__init__(self)
        repo.__init__(self)
        self.ID=ID

    def startProcessing(self):
        if self.ID=='A':
            self.remainTime=23*60
        elif self.ID=='B':
            self.remainTime=22*60
        elif self.ID=='C':
            self.remainTime=16*60
        elif self.ID=='D':
            self.remainTime=18*60

    def load(self,w:waferGroup):
        if self.remainTime is None:
            if w.verifyStep(self.ID): # 确认工艺路径正确
                ret=repo.load(self,w)
                if ret:
                    if len(self.allGroup)==self.maxNum:
                        self.startProcessing() # 装满了就启动加工
                    else:
                        return True
                else:
                    return False
            else:
                return False
        else:
            return False

    def unload(self,ID):
        if self.remainTime is None:
            return repo.unload(self,ID)
        else:
            return False

    def update(self):
        if factoryTask.update(self):
            for i in self.allGroup:
                i.nextStep()


# 问题1：只有加工站ABCD是factory（但必须先经过缓冲区）
# 问题2：不必先经过缓冲区
# 问题3：装卸站（12）车交界和右边交互为真空、和左边交互为大气，状态需10分钟转换。也就是说装卸站（boxRepo('UL')）作为factory

class game:
    def __init__(self):
        self.mainRepo = boxRepo('mainRepo')
        self.ULStatA = boxRepo('UL')
        self.ULStatB = boxRepo('UL')
        self.t1 = boxTruck([self.mainRepo, self.ULStatA, self.ULStatB])

        self.mergeStat = repo()
        self.tA = truckA([self.ULStatA, self.ULStatB, self.mergeStat])

        self.bufferStat = repo()
        self.workA = factoryRepo('A')
        self.workB = factoryRepo('B')
        self.workC = factoryRepo('C')
        self.workD = factoryRepo('D')
        self.tB = truckB([self.mergeStat, self.bufferStat, self.workA, self.workB, self.workC, self.workD])

    def getProgress(self):
        ret = 0
        for i in allWafer:
            ret += i.getProgress()
        return ret

    def update(self):
        self.t1.update()
        self.tA.update()
        self.tB.update()
        self.workA.update()
        self.workB.update()
        self.workC.update()
        self.workD.update()
        return self.getProgress() # 统计每个晶圆盒的加工完成情况（实际应该着重规划没完成的）
